package waveAlgorithm.entity;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.plaf.SliderUI;

import org.apache.log4j.Logger;

import waveAlgorithm.control.Controler;

/**
 * @since Oct 17, 2011
 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
 * @version $Id$
 * 
 */
public class Process implements Runnable {
	private String id;
	private HashMap<String, Process> neigh;
	private int numOfNeigh;
	private HashMap<String, Boolean> recepit;
	private Process silentNeigh;
	private int rcptUnreceived;
	private HashMap<String, Process> mapSilentNeighs;

	public boolean end;

	private static Logger logger = Logger.getLogger(Process.class);

	/**
	 * Constructor a Process with a unique id.
	 * 
	 * Constructor Method
	 * 
	 * @param id
	 */
	public Process(String id) {
		this.id = id;
		this.neigh = new HashMap<String, Process>();
		this.mapSilentNeighs = new HashMap<String, Process>();
		this.numOfNeigh = 0;
		this.recepit = new HashMap<String, Boolean>();
		this.end = false;
	}

	/**
	 * This method contains the core algorithm.
	 * 
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public synchronized void run() {

		try {
			this.wait(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if (neigh.size() == 1) {
			Iterator iter = neigh.entrySet().iterator();
			Map.Entry<String, Process> etr = (Map.Entry<String, Process>) iter
					.next();
			this.silentNeigh = this.neigh.get(etr.getKey());
			if (silentNeigh == null) {
				logger.error(" run()    xxxxxxxxxxxxxxxxx" + this.id
						+ "     silentNeigh == null           ");
			}
			logger.info("LeafNode -" + this.id
					+ "-    has found its silent neighbor     "
					+ this.silentNeigh.getId());
		} else {
			findSilentNeigh();
		}

		notifySilentNeigh();

		while (true) {
			if (getCountOfFalseRcpt() == 0) {
				decide();
				this.end = true;
				
				Iterator it = this.neigh.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, Process> ety = (Map.Entry<String, Process>) it
							.next();
					ety.getValue().end = true ;
					}
				
				
				break;
			}

			if (this.end == true) {
				Iterator it = this.neigh.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, Process> ety = (Map.Entry<String, Process>) it
							.next();
					ety.getValue().end = true ;
					}
				break;
//				Iterator it = this.neigh.entrySet().iterator();
//				while (it.hasNext()) {
//					Map.Entry<String, Process> ety = (Map.Entry<String, Process>) it
//							.next();
//					if (ety.getValue().end == true) {
//						this.end = true;
//						break;
//					}
//				}
			}

		}

		logger.info(this.id + "           end.");
		Controler.numEnd++;
		// if (getCountOfFalseRcpt() == 0) {
		// decide();
		// }

	}

	/**
	 * 
	 * @description to decide.
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 21, 2011 3:10:12 PM
	 */
	private void decide() {
		logger.warn(this.id + " decide.");

	}

	/**
	 * 
	 * @description to send a tok to current process' silent neighbor.
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 21, 2011 3:09:37 PM
	 */
	private void notifySilentNeigh() {
		if (this.silentNeigh == null) {
			logger.error("  notifySilentNeigh()        xxxxxxxxxxxxxxxxx"
					+ this.id + "     silentNeigh == null           ");

		}
		if (this.silentNeigh != null) {
			this.silentNeigh.getRecepit().put(this.id, true);
			logger.info(this.id + " has notified its silent neighbor        "
					+ this.silentNeigh.getId());

		}

	}

	/**
	 * 
	 * @description to find the silent neighbor.
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 21, 2011 3:08:44 PM
	 */
	private void findSilentNeigh() {
		while (this.silentNeigh == null) {
			Iterator iter = this.recepit.entrySet().iterator();
			Map.Entry<String, Boolean> entry = null;
			while (iter.hasNext()) {
				if (mapSilentNeighs.size() == 1) {
					break;
				}
				entry = (Entry<String, Boolean>) iter.next();
				if (entry.getValue()) {
					mapSilentNeighs.remove(entry.getKey());
				}
			}
			if (mapSilentNeighs.size() == 1) {

				Iterator it = this.mapSilentNeighs.entrySet().iterator();
				if (it.hasNext()) {
					Map.Entry<String, Process> ety = (Entry<String, Process>) it
							.next();
					this.silentNeigh = ety.getValue();
					logger.debug(this.id + "         got silent neigh.");
				}

			}

		}

		/*
		 * Process tempSilentNeigh = null; while (this.silentNeigh == null) { //
		 * logger.debug(this.id+"            silent neighbor is null        ")
		 * // ; Iterator iter = this.recepit.entrySet().iterator(); int
		 * trueCount = 0; Map.Entry<String, Boolean> entry = null; while
		 * (iter.hasNext()) { entry = (Entry<String, Boolean>) iter.next(); if
		 * (entry.getValue()) { trueCount++; } else { //
		 * logger.debug(this.id+entry.getKey()+"                        ");
		 * tempSilentNeigh = this.neigh.get(entry.getKey()); } } if
		 * ((recepit.size() - trueCount) == 1) {
		 * 
		 * // logger.debug(this.id + //
		 * "                in                 if ((recepit.size()-trueCount)==1) {"
		 * ); // logger.debug(this.id + //
		 * "                tempSilentNeigh      "+ tempSilentNeigh.id);
		 * this.silentNeigh = tempSilentNeigh;
		 * 
		 * }
		 * 
		 * }
		 */

		/*
		 * 
		 * rcptUnreceived = this.neigh.size(); while (rcptUnreceived > 1) {
		 * Iterator it = this.recepit.entrySet().iterator(); int falseProcess =
		 * this.neigh.size(); Map.Entry<String, Boolean> etr = null; //
		 * logger.debug
		 * (this.id+"               falseProcess count                         "
		 * +falseProcess); while (it.hasNext()) {
		 * 
		 * etr = (Map.Entry<String, Boolean>) it.next();
		 * 
		 * if (etr.getValue() == false) { String falseProcessID = etr.getKey();
		 * // logger.debug(
		 * "falseProcessID                                                  "
		 * +falseProcessID); } else if (etr.getValue() == true) { //
		 * logger.debug(this.id + "                 falseProcess--");
		 * falseProcess--; } else if (falseProcess == 1) {
		 * logger.debug(".............." + this.id + " got silent neighbor  " +
		 * etr.getKey());
		 * 
		 * silentNeigh = this.neigh.get(etr.getKey()); //
		 * logger.debug("silent neighbor               "+silentNeigh); if
		 * (silentNeigh == null) {
		 * logger.error("  findSilentNeigh()        xxxxxxxxxxxxxxxxx  " +
		 * this.id + "     silentNeigh == null           ");
		 * 
		 * } logger.info("TreeNode  -" + this.id +
		 * "-   has found its silent neighbor     " + silentNeigh.getId()); }
		 * 
		 * }
		 * 
		 * 
		 * rcptUnreceived = falseProcess;
		 * 
		 * }
		 */

	}

	/**
	 * 
	 * @return
	 * @description to get the count of neighbor who haven't sent a tok to
	 *              current process.
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 21, 2011 3:07:25 PM
	 */
	private int getCountOfFalseRcpt() {
		Iterator it = this.recepit.entrySet().iterator();
		int falseProcess = this.recepit.size();
		Map.Entry<String, Boolean> etr = null;
		while (it.hasNext()) {
			etr = (Map.Entry<String, Boolean>) it.next();

			if (etr.getValue() == true)
				falseProcess--;
		}
		// logger.debug(this.id+ "      false count       " +falseProcess);
		return falseProcess;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	// public HashMap<String, Process> getNeigh() {
	// return neigh;
	// }

	/**
	 * 
	 * @param neigh
	 * @description to add a neighbor.
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 21, 2011 2:50:01 PM
	 */
	public void setNeigh(Process neighbor) {
		this.neigh.put(neighbor.getId(), neighbor);
		this.recepit.put(neighbor.getId(), false);
		this.mapSilentNeighs.put(neighbor.getId(), neighbor);
		// logger.debug("        "+this.id + "       got         " +
		// neighbor.getId()
		// + "          as a neighbor.");
	}

	// public int getNumOfNeigh() {
	// return numOfNeigh;
	// }
	//
	// public void setNumOfNeigh(int numOfNeigh) {
	// this.numOfNeigh = numOfNeigh;
	// }

	/**
	 * 
	 * @return
	 * @description to return the recepit of current process.
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 21, 2011 3:15:00 PM
	 */
	public HashMap<String, Boolean> getRecepit() {
		return recepit;
	}

	// public void setRecepit(HashMap<String, Boolean> recepit) {
	// this.recepit = recepit;
	// }

	/**
	 * to return current process' id when printed.
	 * 
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return id;
	}

	// public static void main(String[] args) {
	// Process p = new Process("a");
	// System.out.println(p);
	// }
}
